package com.smartstate.admin.biz.service.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smartstate.admin.biz.entity.dto.RolePermissionDto;
import com.smartstate.admin.biz.entity.bo.*;
import com.smartstate.admin.biz.entity.dto.PermissionDto;
import com.smartstate.admin.biz.entity.dto.PermissionSearchDto;
import com.smartstate.admin.biz.entity.vo.PermissionVo;
import com.smartstate.admin.biz.mapper.*;
import com.smartstate.admin.biz.service.PermissionService;
import com.smartstate.admin.biz.util.UserUtils;
import com.smartstate.common.base.constants.BizConstants;
import com.smartstate.common.base.exception.CommonException;
import com.smartstate.common.feign.entity.bo.Enterprise;
import com.smartstate.common.feign.entity.bo.EnterpriseIdPermission;
import com.smartstate.common.feign.entity.dto.EnterprisePermissionDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service("permissionService")
@Slf4j
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService {

    @Resource
    private RolePermissionMapper rolePermissionMapper;

    @Resource
    private RoleMapper roleMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Override
    public List<PermissionVo> findPermissionByUserId(String id) {
        return baseMapper.findPermissionByUserId(id);
    }

    @Override
    public List<PermissionVo> findAppPermissionByUserId(String id) {
        return baseMapper.findAppPermissionByUserId(id);
    }

    @Override
    public List<PermissionVo> findAuthorityByRoleId(String id) {
        return baseMapper.findAuthorityByRoleId(id);
    }

    @Override
    public Map<String, Object> getPermissionByUserId(String id) {
        List<PermissionVo> permissionList = baseMapper.getPermissionByUserId(id);
        return treePermission1(permissionList);
    }

    @Override
    public Map<String, Object> getAppPermissionByUserId(String id) {
        List<PermissionVo> permissionList = baseMapper.getAppPermissionByUserId(id);
        return treePermission1(permissionList);
    }

    @Override
    public IPage<PermissionVo> queryPermissionList(PermissionSearchDto permissionSearchDto) {
        Page<PermissionVo> page = permissionSearchDto.initPage();
        User user = userMapper.selectById(UserUtils.getLoginUser().getId());
        user.setIsAdmin(0);
        List<PermissionVo> permissionVos = baseMapper.selectPermissionList(page, user);
        page.setRecords(permissionVos);
        return page;
    }

    @Override
    public List<Map<String, Object>> queryPermissionTree(PermissionSearchDto permissionSearchDto) {
        User user = userMapper.selectById(UserUtils.getLoginUser().getId());
        List<Permission> permissionList;
        String enterpriseId=permissionSearchDto.getEnterpriseId();
        // 是管理员携带企业编号 查询企业下的权限,不带企业编号查询所有的权限
        if(user.getIsAdmin()!=null&&user.getIsAdmin()==1){
            enterpriseId=null;
            if(permissionSearchDto!=null&&StringUtils.isNotBlank(permissionSearchDto.getEnterpriseId())){
                permissionList = baseMapper.selectByCompId(permissionSearchDto.getEnterpriseId());
            }else{
                QueryWrapper<Permission> permissionQueryWrapper = new QueryWrapper<Permission>().eq("STATUS", 1).eq("IS_WEB",0).orderByAsc("SORT").orderByDesc("CREATE_TIME");
                permissionList = baseMapper.selectList(permissionQueryWrapper);
            }
            //如果不是管理员,就查询该用户所属企业的所有权限id
        }else{
            permissionList = baseMapper.selectByCompId(user.getEnterpriseId());
            enterpriseId=user.getEnterpriseId();
        }
        return treePermission(permissionList,enterpriseId);
    }

    @Override
    public List<Map<String, Object>> queryAppPermissionTree(PermissionSearchDto permissionSearchDto) {
        User user = userMapper.selectById(UserUtils.getLoginUser().getId());
        List<Permission> permissionList;
        String enterpriseId=permissionSearchDto.getEnterpriseId();
        // 是管理员携带企业编号 查询企业下的权限,不带企业编号查询所有的权限
        if(user.getIsAdmin()!=null&&user.getIsAdmin()==1){
            enterpriseId=null;
            if(permissionSearchDto!=null&&StringUtils.isNotBlank(permissionSearchDto.getEnterpriseId())){
                permissionList = baseMapper.selectAppByCompId(permissionSearchDto.getEnterpriseId());
            }else{
                QueryWrapper<Permission> permissionQueryWrapper = new QueryWrapper<Permission>().eq("STATUS", 1).eq("IS_WEB",1).orderByAsc("SORT").orderByDesc("CREATE_TIME");
                permissionList = baseMapper.selectList(permissionQueryWrapper);
            }
            //如果不是管理员,就查询该用户所属企业的所有权限id
        }else{
            permissionList = baseMapper.selectAppByCompId(user.getEnterpriseId());
            enterpriseId=user.getEnterpriseId();
        }
        return treePermission(permissionList,enterpriseId);
    }

    @Override
    public PermissionVo queryPermissionById(String id) {
        Permission permission = baseMapper.selectOne(new QueryWrapper<Permission>().eq("id",id).eq("IS_WEB",0));
        return new PermissionVo().buildVo(permission);
    }

    @Transactional(rollbackFor = CommonException.class)
    @Override
    public boolean saveOrUpdatePermission(PermissionDto permissionDto) {
        permissionDto.setUserId(UserUtils.getLoginUser().getId());
        if (StringUtils.isBlank(permissionDto.getPid())) {
            permissionDto.setPid(BizConstants.NONE_NODE);
        }
        Permission permission = new Permission();
        permission.buildBo(permissionDto);
        if (StringUtils.isBlank(permissionDto.getId())) {
            permission.setCreateUser(permissionDto.getUserId());
            permission.setStatus(BizConstants.YES);
            baseMapper.insert(permission);
        } else {
            permission.setUpdateUser(permissionDto.getUserId());
            baseMapper.updateById(permission);
        }
        if (permissionDto.getApiConfig() != null && !permissionDto.getApiConfig().isEmpty()) {
            baseMapper.delete(new QueryWrapper<Permission>().eq("pid", permission.getId()));
            List<Permission> permissionList = new ArrayList<>();
            for (PermissionDto permissionDto1 : permissionDto.getApiConfig()) {
                Permission permission1 = new Permission();
                permission1.setPid(permission.getId());
                permission1.setType(permissionDto1.getType());
                permission1.setUrlPath(permissionDto1.getUrlPath());
                permission1.setCreateUser(permissionDto.getUserId());
                permission1.setStatus(BizConstants.YES);
                permission1.setName(permissionDto1.getName());
                permissionList.add(permission1);
            }
            baseMapper.insertBatch(permissionList);
        }
        return true;
    }

    /**
     * 递归删除所有节点
     */
    @Transactional(rollbackFor = CommonException.class)
    @Override
    public boolean deletePermission(String id) {
        boolean flag = false;
        List<Permission> permissions = baseMapper.selectList(new QueryWrapper<Permission>().eq("STATUS", 1).orderByAsc("SORT").orderByDesc("CREATE_TIME"));
        if (permissions.size() > 0) {
            List<Permission> chilrenPermissionList = new LinkedList<>();
            childPermissionList(permissions, id, chilrenPermissionList);
            chilrenPermissionList = chilrenPermissionList.parallelStream().distinct().collect(Collectors.toList());
            if (chilrenPermissionList.size() > 0) {
                List<String> ids = chilrenPermissionList.parallelStream().map(Permission::getId).collect(Collectors.toList());
                if (ids.size() > 0) {
                    List<RolePermission> list = rolePermissionMapper.selectBatchPerIds(ids);
                    if (list.size() > 0) {
                        rolePermissionMapper.deleteBatchIds(list.stream().map(RolePermission::getId).collect(Collectors.toList()));
                    }
                    flag = baseMapper.deleteBatchIds(ids) > 0;
                }
            }
        }
        return flag;
    }


    @Transactional(rollbackFor = CommonException.class)
    @Override
    public boolean deleteBatchPermission(List<String> ids) {
        for(String id:ids){
            this.deletePermission(id);
        }
        return true;
    }
    public void deleteChildrenById(String id){
        //this.baseMapper.s
    }

    @Override
    public List<PermissionVo> getPermissionByRoleId(String id) {
        List<PermissionVo> list = baseMapper.selectByRoleId(id);
        return list;
    }
    @Override
    public List<PermissionVo> getAppPermissionByRoleId(String id) {
        List<PermissionVo> list = baseMapper.selectAppByRoleId(id);
        return list;
    }

    @Override
    public boolean savePermissionAndRole(String roleId, List<RolePermissionDto> rolePermissionDtos) {
        log.info("roleId:"+roleId+"更新权限信息");
        List<RolePermission> list = rolePermissionMapper.selectByRoleId(roleId);
        if (list.size() > 0) {
            rolePermissionMapper.deleteBatchIds(list.parallelStream().map(RolePermission::getId).collect(Collectors.toList()));
        }
        if(rolePermissionDtos==null||rolePermissionDtos.size()==0){
            return true;
        }
        List<RolePermission> collect =rolePermissionDtos.stream().parallel().map(x->{
            RolePermission rolePermission = new RolePermission(x,roleId);
            return rolePermission;
        }).collect(Collectors.toList());
        boolean b = rolePermissionMapper.insertBatch(collect) > 0;
        log.info("roleId:"+roleId+"更新权限信息完成");

        return b;
    }




    private List getList(Map<String, Object> mapArr, Permission treeNode, List<Permission> menuCommon, List<String> stringList) {
        mapArr.put("id", treeNode.getId());
        List<?> childrens = getOrgChild(treeNode.getId(), menuCommon, stringList);
        if (childrens.size() <= 0) {
            stringList.add(treeNode.getId());
        }
        return stringList;
    }

    private List<?> getOrgChild(String id, List<Permission> menuCommon, List<String> stringList) {
        List<Object> lists = new ArrayList<>();
        for (Permission a : menuCommon) {
            Map<String, Object> childArray = new LinkedHashMap<>();
            if (a.getPid().equals(id)) {
                getList(childArray, a, menuCommon, stringList);
                lists.add(childArray);
            }
        }
        return lists;
    }

    /**
     * 获取某个父节点下面的所有子节点
     */
    private List<Permission> childPermissionList(List<Permission> permissionList, String pid, List<Permission> childPerm) {
        for (Permission mu : permissionList) {
            if (mu.getId().equals(pid)) {
                childPerm.add(mu);
            }
            //遍历出父id等于参数的id，add进子节点集合
            if (mu.getPid().equals(pid)) {
                //递归遍历下一级
                childPerm.add(mu);
                childPermissionList(permissionList, mu.getId(), childPerm);
            }
        }
        return childPerm.parallelStream().distinct().collect(Collectors.toList());
    }

    public List<Map<String, Object>> treePermission(List<Permission> permissions,String enterpriseId) {
        Map<String, List<EnterpriseIdPermission>> collect=null;
        List<Map<String, Object>> list = new ArrayList<>();
        for (Permission treeNode : permissions) {
            Map<String, Object> mapArr = new LinkedHashMap<String, Object>();
            if (treeNode.getPid().equals(BizConstants.NONE_NODE)) {
                setTreeMap(mapArr, treeNode, permissions,collect);
                list.add(mapArr);
            }
        }
        return list;
    }

    private List<?> orgChild(String id, List<Permission> menuCommon,Map<String, List<EnterpriseIdPermission>> collect) {
        List<Object> lists = new ArrayList<>();
        for (Permission a : menuCommon) {
            Map<String, Object> childArray = new LinkedHashMap<>();
            if (null != a.getPid()) {
                if (a.getPid().equals(id)) {
                    setTreeMap(childArray, a, menuCommon,collect);
                    lists.add(childArray);
                }
            }
        }
        return lists;
    }

    private void setTreeMap(Map<String, Object> mapArr, Permission treeNode, List<Permission> menuCommon,Map<String, List<EnterpriseIdPermission>> collect) {
        mapArr.put("id", treeNode.getId());
        mapArr.put("name", treeNode.getName());
        mapArr.put("pid", treeNode.getPid());
        mapArr.put("code", treeNode.getCode());
        mapArr.put("urlPath", treeNode.getUrlPath());
        mapArr.put("icon", treeNode.getIcon());
        mapArr.put("type", treeNode.getType());
        mapArr.put("sort", treeNode.getSort());
        if(collect!=null&&collect.size()>0){
            mapArr.put("roleType",collect.get(treeNode.getId()).get(0).getPermissionType());
        }else{
            mapArr.put("roleType", 3);
        }
        mapArr.put("component", treeNode.getComponent());
        List<?> childrens = orgChild(treeNode.getId(), menuCommon,collect);
        if (childrens.size() > 0) {
            mapArr.put("hasChildren", true);
        } else {
            mapArr.put("hasChildren", false);
        }
        mapArr.put("childrens", childrens);
    }

    private Map<String, Object> treePermission1(List<PermissionVo> permissions) {
        Map<String, Object> result = new LinkedHashMap<>();
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> meun = new LinkedHashMap<>();
        for (PermissionVo treeNode : permissions) {
            Map<String, Object> mapArr = new LinkedHashMap<String, Object>();
            if (treeNode.getPid().equals(BizConstants.NONE_NODE)) {
                setTreeMap1(mapArr, treeNode, permissions, meun);
                list.add(mapArr);
            }
        }
        result.put("permissions", list);
        result.put("buttons", meun);
        return result;
    }

    private List<?> orgChild1(String id, List<PermissionVo> menuCommon, Map<String, Object> menus) {
        List<Object> lists = new ArrayList<>();
        for (PermissionVo a : menuCommon) {
            Map<String, Object> childArray = new LinkedHashMap<>();
            if (null != a.getPid()) {
                if (a.getPid().equals(id)) {
                    setTreeMap1(childArray, a, menuCommon, menus);
                    if (a.getType().equals(0)) {
                        lists.add(childArray);
                    }
                }
            }
        }
        return lists;
    }

    private void setTreeMap1(Map<String, Object> mapArr, PermissionVo treeNode, List<PermissionVo> menuCommon, Map<String, Object> menus) {
        List<Object> list = new ArrayList<>();
        if (treeNode.getType().equals(0)) {
            mapArr.put("id", treeNode.getId());
            mapArr.put("name", treeNode.getName());
            mapArr.put("pid", treeNode.getPid());
            mapArr.put("code", treeNode.getCode());
            mapArr.put("urlPath", treeNode.getUrlPath());
            mapArr.put("icon", treeNode.getIcon());
            mapArr.put("type", treeNode.getType());
        } else {
            list.add(treeNode);
            if (menus.containsKey(treeNode.getPidName())) {
                List o = (List) menus.get(treeNode.getPidName());
                o.addAll(list);
            } else {
                menus.put(treeNode.getPidName(), list);
            }
        }
        List<?> childrens = orgChild1(treeNode.getId(), menuCommon, menus);
        if (treeNode.getType().equals(0)) {
            if (childrens.size() > 0) {
                mapArr.put("hasChildren", true);
            } else {
                mapArr.put("hasChildren", false);
            }
            mapArr.put("childrens", childrens);
        }
    }

    public static List<Tree<String>> getPermissionsTree(List<Permission> permissions){
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setChildrenKey("childrens");
        treeNodeConfig.setIdKey("id");
        treeNodeConfig.setParentIdKey("pid");
        List<Tree<String>> build = TreeUtil.build(permissions, "0", treeNodeConfig,
                (treeNode, tree) -> {
                    tree.setId(treeNode.getId());
                    tree.setParentId(treeNode.getPid());
                    tree.setName(treeNode.getName());
                    tree.putExtra("code", treeNode.getCode());
                    tree.putExtra("sort", treeNode.getSort());
                    tree.putExtra("urlPath", treeNode.getUrlPath());
                    tree.putExtra("icon", treeNode.getIcon());
                    tree.putExtra("urlPath", treeNode.getUrlPath());
                });
        return  build;
    }
    public static List<Tree<String>> getPermissionsVOTree(List<PermissionVo> permissionVos){
        List<Permission> permissions = new ArrayList<>();
        for(PermissionVo permissionVo:permissionVos){
            Permission permission = new Permission();
            BeanUtils.copyProperties(permissionVo,permission);
            permissions.add(permission);
        }
        List<Tree<String>> permissionsTree = PermissionServiceImpl.getPermissionsTree(permissions);
        return  permissionsTree;
    }

}
